An extremely unfortunate incident happened last month when I was enthusiastically preparing to write a menu system for my Minecraft server. For some unknown reason, Termius automatically completed what I originally wanted to write as 'cd ./server' to 'rm -rf ./server'. However, I was able to recover over 95% of the data in the end, luckily.
Scope#
- The file is still running in the cache, which means that during the recovery process, you cannot terminate the process or shut down.
Steps#
-
Accidentally delete a file, but the file is occupied by a process.
$ rm test.sh
-
Use the lsof command to list the files that have been deleted but are still occupied by processes.
$ lsof | grep -i delete | grep speed sh 6567 root 4r REG 253,0 865 /home/test.sh(deleted)
- In the above output, the first item 'sh' is the process name, and the second item '6567' is the process ID.
-
Enter the process directory.
$ cd /proc/6567/fd $ ls -la lr-x------. 1 root root 64 July 13 02:10 4 -> /home/test.sh (deleted)
- In the above output, the ninth item '4' is the file descriptor.
-
Recovery
$ cat 4 > /home/test.sh
Recovering a Folder#
-
If a folder is accidentally deleted, manually recovering it can be cumbersome, especially when dealing with numerous small files. In this case, we can use a small program to perform batch recovery.
-
Before proceeding, you need to export all the files that need to be recovered in Step 1 to a log file. We won't go into too much detail here.
use std::fs; use std::io::Read; fn main() { let mut log_file = fs::File::open("/home/deleted_files.log").unwrap(); // Replace with the path to your file list to be recovered let mut logs = String::new(); log_file.read_to_string(&mut logs).unwrap(); let mut command = String::new(); let mut paths = Vec::new(); let logs = logs.split("\n"); for log in logs { let log = log.split_whitespace().collect::<Vec<&str>>(); if log.len() < 12 { continue; } let number = log[8]; // 8 is the column number where the file descriptor is located, modify according to the actual file let path = log[10]; // 10 is the column number where the original file path is located, modify according to the actual file if !path.starts_with("/home") { // Replace with the target folder you want to recover to continue; } println!("{}: {}", number, path); command.push_str(format!("cat {} > ~/recovery{}\n", number, path).as_str()); let path = path.split("/").collect::<Vec<&str>>(); let path = path[..path.len() - 1].join("/"); let path = format!("~/recovery{}", path); if !paths.contains(&path) { paths.push(path); } } let mut complete_cmd = String::new(); for path in paths { complete_cmd.push_str(format!("mkdir -p {}\n", path).as_str()); } println!("{}", complete_cmd); complete_cmd.push_str(&command); fs::write("recovery.sh", complete_cmd).unwrap(); }
-
Finally, run the generated
recovery.sh
to recover all the files.
Note: For a Minecraft server, player data cannot be directly recovered, and this method cannot guarantee the recovery of all deleted files. Please remember to regularly back up your files and avoid regretting the consequences of accidental deletion!
This article is synchronized to xLog by Mix Space.
The original link is https://blog.rescueme.life/posts/devops/restore-files-deleted-by-rm-but-occupied-by-processes